import { PluginCommand } from "./PluginCommand";
import {
  PluginCADToolFunctionType,
  PluginFunctionType
} from "../../nodeApp/static/lib/crowncad-plugin-sdk-0.0.1";
import { ElementType } from "../modeling/TypeDefine";

var FrameType = {
  TypeL: 0,
  TypeC: 1,
}
export { FrameType };

class FrameDesignToolCommand extends PluginCommand {
  constructor() {
    super();
  }

  frameType = 0;//框类型
  copySurfaceFid = 0;//存放被复制曲面的fid,用于筛选2次抽壳后外橼面和内橼面进行实体偏移面
  selDatumPlane = [];//定位基准面
  externalSurface = {};//外框抽壳的曲面
  bottomSurface = {};//多厚度面抽壳的底面
  datumPlaneId = 0;//定位基准面id
  offset = 0;//偏移距离
  bFrameLength = 0;//外框外面到内橼框内面距离
  inFrameLength = 0;//外框长度
  exFrameLength = 0;//内框长度
  exFrameThickness = 0;//外框厚度
  inFrameThickness = 0;//内框厚度
  bFrameThickness = 0;//框底厚度
  featureIdList = []

  //关闭活跃的命令面板
  closeActiveCmd() {
    if (this.toolQuery) {
      this.toolQuery.closeActiveCmd();
    }
  }

  /**
   * 基准面创建偏移面并返回偏移面特征获取偏移面元素信息
   * @param datumId 偏移基准面
   * @param dis 偏移距离
   * @param reverse 偏移方向
   * @param cb 返回元素信息和特征id
   */
  async createDatumByDistance(datumId, dis, reverse, cb) {
    let res = await this.createPlaneByDistanceIncrement(datumId, dis, reverse);
    if (res?.code === 200 && res?.data?.modelData?.status === 0) {
      let modelData = res?.data?.modelData
      let featureId = modelData?.currentFeature?.map(item => item.id);
      let entities = await this.getEntitiesByFeatureId(res?.data?.modelData?.currentFeature?.map(item => item.id)[0]);
      let entityIds = entities?.data?.entities.map(item => item.id);
      if (entityIds) {
        let result = await this.command.common.setEntityVisibleIncrement({
          entityIds: entityIds,
          status: 0
        });
        let element = await this.getElementsByFeatureId(modelData?.currentFeature[0]?.id)
        let elementsInfo = element?.data?.elements?.filter(item => item.type === ElementType.DATUMPLANE);
        cb(elementsInfo, featureId)
      }
    } else {
      let msg = res?.data?.modelData;
      this.eventBusAlertMsg(msg, 'error');
    }
  }

  /**
   * 创建偏移面
   * @param datumId 基准面id
   * @param dis 偏移距离
   * @param reverse 是否反向
   */

  createPlaneByDistanceIncrement(datumId, dis, reverse,) {
    return new Promise(resolve => {
      this.command.datum.createPlaneByDistanceIncrement({
        planeId: datumId,
        invertNormal: 0,
        paralDis: dis,
        reverse: reverse
      }).then(async res => {
        if (res?.code === 200 && res?.data?.modelData?.status === 0) {
          let featureIds = res?.data.modelData?.data?.featureDatas.map(item => item.id);
          await this.setFeatureIdList(featureIds);
          resolve(res)
        } else {
          await this.deleteFeature(this.featureIdList);
        }
      })
    })
  }

  /**
   * 根据元素id获取实体信息
   * @param id
   */
  getEntitiesByFeatureId(id) {
    return new Promise(resolve => {
      this.toolQuery.getEntitiesByFeatureId(id).then(res => {
        resolve(res)
      })
    })
  }

  /**
   * 根据元素id获取元素信息
   * @param id
   */
  getElementsByFeatureId(id) {
    return new Promise(resolve => {
      this.query.getElementsByFeatureId(id).then(res => {
        resolve(res)
      })
    })
  }


  /**
   * 预裁剪曲面
   * @param surface 被裁曲面
   * @param trimEle 裁剪工具--基准面
   * @param cb
   */
  previewTrimSurface(surface, trimEle, cb) {
    if (this.request) {
      this.request.execFunction(PluginCADToolFunctionType.previewTrimSurface, {
        surfaceElement: surface,
        trimElement: trimEle
      }).then(res => {
        cb(res);
      });
    }
  }

  /**
   * 根据元素id获取所在实体Id
   * @param faceId 面Id列表
   * @param cb 返回实体Id数组
   */
  getElementsEntityIdsByIds(faceId, cb) {
    this.query.getElementsByIds(faceId).then(res => {
      if (res?.code === 200) {
        let data = res?.data.elements;
        let entityRefIds = data?.map(item => item.params.entityRefId);
        cb(entityRefIds);
      }
    });
  }

  /**
   * 复制曲面
   * @param faceIds 面Id列表
   * @param entityIds 面所属的实体Id列表
   * @param cb 复制曲面的返回值
   */
  copySurface(faceIds, entityIds, cb) {
    this.command.clearCommand()
    this.command.surface.copySurfaceIncrement({
      surfaceIds: faceIds,
      instanceIds: entityIds,
    }).then(async res => {
      if (res?.code === 200 && res?.data?.modelData?.status === 0) {
        let featureIds = res?.data.modelData?.data?.featureDatas.map(item => item.id);
        await this.setFeatureIdList(featureIds);
        cb(res)
      } else {
        await this.deleteFeature(this.featureIdList);
      }
    })
  }

  /**
   * 创建L形框
   * @param params.paramsexFrameThickness 外橼框厚度
   * @param params.bFrameThickness 框底厚度
   * @param params.trimEle 裁剪工具
   * @param params.selRefSurface 被裁曲面
   * @param params.frameType 框类型
   */
  async createLFrame(params) {
    this.offset = params?.offset;
    this.bFrameLength = params?.bFrameLength;
    this.inFrameLength = params?.inFrameLength;
    this.exFrameLength = params?.exFrameLength;
    this.inFrameThickness = params?.inFrameThickness;
    this.exFrameThickness = params.exFrameThickness;
    this.bFrameThickness = params.bFrameThickness;
    this.frameType = params.frameType;
    this.datumPlaneId = params?.selDatumPlane?.map(item => item.id)[0];
    await this.trimSurface(params.trimEle, params.selRefSurface, params?.keepTags, params?.newSrfData, params?.oldSrfData);
  }

  /**
   * 创建C形框
   * @param params.offset 偏移距离
   * @param params.bFrameLength C形框外缘到内缘距离
   * @param params.inFrameLength 外框长度
   * @param params.exFrameLength 内框长度
   * @param params.inFrameThickness 内橼框厚度
   * @param params.exFrameThickness 外橼框厚度
   * @param params.bFrameThickness 框底厚度
   * @param params.trimEle 裁剪工具
   * @param params.selRefSurface 被裁曲面
   * @param params.frameType 框类型
   */
  async createCFrame(params) {
    this.offset = params?.offset;
    this.bFrameLength = params?.bFrameLength;
    this.inFrameLength = params?.inFrameLength;
    this.exFrameLength = params?.exFrameLength;
    this.inFrameThickness = params?.inFrameThickness;
    this.exFrameThickness = params?.exFrameThickness;
    this.bFrameThickness = params?.bFrameThickness;
    this.frameType = params?.frameType;
    this.datumPlaneId = params?.selDatumPlane?.map(item => item.id)[0];
    await this.trimSurface(params?.trimEle, params?.selRefSurface, params?.keepTags, params?.newSrfData, params?.oldSrfData);
  }

  /**
   * 裁剪曲面
   * @param trimEle 裁剪工具
   * @param selRefSurface 被裁曲面
   * @param keepTags 保留面标志
   * @param newSrfData
   * @param oldSrfData
   */
  async trimSurface(trimEle, selRefSurface, keepTags, newSrfData, oldSrfData) {
    let limitIds = trimEle.map(item => item.id);
    let res = await this.trimSurfaceIncrement(trimEle, selRefSurface, keepTags, newSrfData, oldSrfData);
    this.clearPreview();
    let data = res?.data?.modelData?.data;
    let surfaceIds = data?.addElements.filter(item => item.type === ElementType.FACE).map(item => item.id);//裁剪结果面
    let getKeepSurface = [];//获取符合条件的保留面
    for ( const id of surfaceIds ) {
      let measure = [];
      for ( const item of limitIds ) {
        let isCross = await this.getMeasure([id, item]);
        measure.push(isCross);
      }
      if (measure.every(item => item === true)) {
        getKeepSurface.push(id);
      }
    }
    let planeEids = [];//存放保留面+2个平面区域实体id，用于缝合曲面
    let curveIds = data?.addElements.filter(item => item.type === ElementType.EDGE).map(item => item.id);//获取裁剪曲面后的所有边线id
    let fid = data?.featureDatas?.filter(item => item.type === 'TrimSurface').map(item => item.id)[0];//获取裁剪曲面的特征id
    let elements = await this.query.getElementsByFeatureId(fid);//通过特征id获取元素信息
    let entityIds = [];
    for ( const curveId of curveIds ) {
      let boundingSurface = await this.getBoundedFaceIdsByFaceOrEdge(curveId);//获取所有边线的相邻面
      if (boundingSurface[0] === getKeepSurface[0]) {//如果相邻面=保留面,获取保留面上的两条边线曲线id
        let eid = elements.data.elements.filter(item => item.id === curveId).map(item => item.params.entityRefId);
        entityIds = [...eid];//获取保留曲面的实体id
        let planSurfaceFid = await this.planeSurface(curveId);//创建平面区域
        let planeSurfaceEntity = await this.toolQuery.getEntitiesByFeatureId(planSurfaceFid);//获取两个边线创建平面区域后的特征id
        let entityId = planeSurfaceEntity?.data?.entities[0]?.id;//获取创建平面区域后的两边线的实体id
        planeEids.push(entityId);
      }
    }
    planeEids.push(...entityIds);
    this.copySurfaceFid = data?.featureDatas?.filter(item => item.type === "CopySurface")[0]?.id;
    await this.knitSurface(planeEids);//两个平面区域+裁剪曲面实体id
  }

  /**
   * 裁剪曲面特征接口
   * @param trimEle 裁剪工具
   * @param selRefSurface 被裁曲面
   * @param keepTags 保留面标志
   * @param newSrfData
   * @param oldSrfData
   */
  trimSurfaceIncrement(trimEle, selRefSurface, keepTags, newSrfData, oldSrfData) {
    return new Promise(resolve => {
      let surfaceId = selRefSurface.map(item => item.id);
      let limitIds = trimEle.map(item => item.id);
      this.command.surface.trimSurfaceIncrement({
        limitIds: limitIds,
        surfaceIds: surfaceId,
        keepMode: 0,
        keepTags: keepTags,
        oldSurfaceIds: oldSrfData,
        newSurfaceIds: newSrfData,
      }).then(async res => {
        if (res?.code === 200 && res?.data?.modelData?.status === 0) {
          let featureIds = res?.data.modelData?.data?.featureDatas.map(item => item.id);
          await this.setFeatureIdList(featureIds);
          resolve(res)
        } else {
          await this.deleteFeature(this.featureIdList);
        }
      })
    })
  }

  /**
   * 平面区域
   * @param boundingIds 边界曲线或草图Id列表
   */
  async planeSurface(boundingIds) {
    this.command.clearCommand();
    let ids = [];
    ids.push(boundingIds)
    let planeData = await this.command.surface.planeSurfaceIncrement({
      boundingEntities: ids,
    },)
    if (planeData?.code === 200 && planeData?.data?.modelData?.status === 0) {
      let featureIds = planeData?.data.modelData?.data?.featureDatas.map(item => item.id);
      await this.setFeatureIdList(featureIds);
      return planeData?.data?.modelData?.currentFeature[0].id
    } else {
      await this.deleteFeature(this.featureIdList);
    }
  }

  /**
   * 缝合特征接口
   * @param surfacesId 被缝合曲面entityIds数组
   */
  knitSurfaceIncrement(surfacesId) {
    return new Promise(resolve => {
      this.command.clearCommand();
      this.command.surface.knitSurfaceIncrement({
        surfaces: surfacesId,
        controlGap: 0,
        tolerance: 0.001,
      }).then(async res => {
        if (res?.code === 200 && res?.data?.modelData?.status === 0) {
          let featureIds = res?.data.modelData?.data?.featureDatas.map(item => item.id);
          await this.setFeatureIdList(featureIds);
          resolve(res)
        } else {
          await this.deleteFeature(this.featureIdList);
        }
      })
    })
  }

  /**
   * 多厚度面抽壳特征接口
   * @param removeFaceIds 抽壳面1faceId
   * @param thickness 抽壳面1厚度
   * @param multiFacesIds 多抽壳面faceIds
   * @param multiThickness 多抽壳面厚度列表
   */
  createShellIncrement(removeFaceIds, thickness, multiFacesIds, multiThickness) {
    return new Promise(resolve => {
      this.command.clearCommand();
      this.command.solid.createShellIncrement({
        removeFaces: removeFaceIds,
        thickenSolid: 0,
        thickness: thickness,
        outward: 0,
        multiFaces: multiFacesIds,
        multiThickness: multiThickness
      }, "").then(async res => {
        if (res?.code === 200 && res?.data?.modelData?.status === 0) {
          let featureIds = res?.data.modelData?.data?.featureDatas.map(item => item.id);
          this.setFeatureIdList(featureIds);
          resolve(res)
        } else {
          await this.deleteFeature(this.featureIdList);
        }
      })
    })
  }

  setFeatureIdList(arrA) {
    if (arrA.length !== 0) {
      const featureIds = arrA.filter(element => !this.featureIdList.includes(element));
      this.featureIdList.push(...featureIds);
    }
  }

  /**
   * 缝合
   * @param surfacesId 被缝合曲面entityIds数组
   */
  async knitSurface(surfacesId) {
    let res = await this.knitSurfaceIncrement(surfacesId);
    let data = res?.data?.modelData?.data
    let fids = data?.featureDatas?.filter(item => item.type === 'Plane')?.map(item => item.id);
    let edges = data?.addElements.filter(item => fids.includes(item.fid));//获取缝合面后的
    for ( const item of edges ) {
      let isCross = await this.getMeasure([item.id, this.datumPlaneId]);//判断被缝合的两个平面区域与定位基准面的距离
      if (!isCross) {
        this.externalSurface = item;
      } else {
        //与定位基准面贴合的平面区域
        this.bottomSurface = item;
      }
    }
    let removeFaceIds = [];
    let multiFacesIds = [];
    let multiThickness = [];
    edges?.forEach(item => {
      if (item.id === this.externalSurface?.id) {
        removeFaceIds.push(item.id);
      } else {
        multiFacesIds.push(item.id);
      }
    });
    multiThickness.push(0);
    await this.createShellOne(removeFaceIds, multiFacesIds, multiThickness)
  }

  async createShellOne(removeFaceIds, multiFacesIds, multiThickness) {
    let createShellOne = await this.createShellIncrement(removeFaceIds, this.bFrameLength, multiFacesIds, multiThickness);
    if (createShellOne?.code === 200) {
      let data = createShellOne?.data?.modelData?.data;
      let fids = data?.featureDatas?.filter(item => item.type === 'Shell')?.map(item => item.id);//获取第一次抽壳的fid;
      let bottomSurfaceId = data?.addElements.filter(item => item.type === ElementType.FACE && item.fid === this.bottomSurface.fid)?.map(item => item.id);
      let inSurfaceId = data?.addElements.filter(item => fids.includes(item.fid) && item.type === ElementType.FACE)?.map(item => item.id);
      let removeSurfaceId = data?.addElements.filter(item => item.type === ElementType.FACE && item.id !== bottomSurfaceId[0] && item.id !== inSurfaceId[0]).map(item => item.id);
      this.bottomSurface = {};
      multiFacesIds = [];
      multiFacesIds = [...bottomSurfaceId, ...inSurfaceId];
      multiThickness = [];
      multiThickness.push(this.bFrameThickness);
      multiThickness.push(this.inFrameThickness);
      if (this.bFrameLength > this.exFrameThickness) {
        await this.createShellTwo(removeSurfaceId, multiFacesIds, multiThickness);
      } else {
        this.eventBusAlertMsg("框结构创建成功", 'success')
      }
    }
  }

  async createShellTwo(removeSurfaceId, multiFacesIds, multiThickness) {
    let createShellTwo = await this.createShellIncrement(removeSurfaceId, this.exFrameThickness, multiFacesIds, multiThickness);
    if (createShellTwo?.code === 200 && createShellTwo.data.modelData.status === 0) {
      let data = createShellTwo?.data?.modelData?.data;
      let shellSurfaceIds = data?.addElements?.filter(item => item.type === ElementType.FACE && item.fid === this.externalSurface.fid).map(item => item.id);
      let selSurfaceId = data?.modElements?.filter(item => item.fid === this.copySurfaceFid)?.map(item => item.id);
      let boundFacesIds = await this.getBoundedFaceIdsByFaceOrEdge(selSurfaceId[0]);
      let exFaceOffsetDis = this.calculateDis(this.exFrameLength, this.offset);
      if (exFaceOffsetDis !== 0) {
        let exFaceId = shellSurfaceIds?.filter(item => boundFacesIds.includes(item));
        let offsetExFaceRes = await this.offsetSurface(exFaceId, exFaceOffsetDis);
        if ((offsetExFaceRes?.code !== 200) || (offsetExFaceRes?.data?.modelData?.status === -1)) {
          return;
        }
      }
      if (this.frameType === FrameType.TypeC) {
        let inFaceOffsetDis = this.calculateDis(this.inFrameLength, this.offset);
        if (inFaceOffsetDis !== 0) {
          let inFaceId = shellSurfaceIds?.filter(item => !boundFacesIds.includes(item));
          let offsetInFaceRes = await this.offsetSurface(inFaceId, inFaceOffsetDis);
          if ((offsetInFaceRes?.code !== 200) || (offsetInFaceRes?.data?.modelData?.status === -1)) {
            return;
          }
        }
      }
      this.featureIdList = [];
      this.eventBusAlertMsg("框结构创建成功", 'success');
    }
  }

  /**
   * 偏移实体面
   * @param offsetFaceId 偏移面Id列表
   * @param distance 偏移距离
   */
  async offsetSurface(offsetFaceId, distance) {
    this.command.clearCommand();
    return await this.command.solid.offsetFacesIncrement({
      offsetFaceIds: offsetFaceId,
      distance: distance,
      reverse: 0,
    }, "")
  }

  /**
   * 删除特征
   * @param featureIds featureId列表
   */
  async deleteFeature(featureIds) {
    this.command.clearCommand();
    let res = await this.command.common.deleteFeatureIncrement({
      featureIds: featureIds
    })
  }

  /**
   * 测量元素之间的距离
   * @param geomIds 被检测元素id列表
   */
  async getMeasure(geomIds) {
    let res = await this.command.evaluate.getMeasureInfoIncrement({geomId: geomIds, instanceId: ['', '']});
    if (res?.data?.modelData?.data?.value?.IsCross) {
      return true;
    }
    return false
  }

  /**
   * 通过面或者边查询与之相邻的所有面
   * @param geomId 元素id
   */
  async getBoundedFaceIdsByFaceOrEdge(geomId) {
    let res = await this.command.query.getBoundedFaceIdsByFaceOrEdgeIncrement({elementId: geomId, instanceId: ''});
    if (res?.code === 200) {
      return res?.data?.modelData?.data?.value?.BoundFaces;
    }
  }

  /**
   * 计算偏移距离
   * @param a 被减数
   * @param b 减数
   */
  calculateDis(a, b) {
    return a - b;
  }
}

const frameDesignToolCommand = new FrameDesignToolCommand()
export { frameDesignToolCommand };